package com.study.cloud.gateway.client.support.springmvc;

import com.study.cloud.gateway.client.core.ApiAnnotationScanner;
import com.study.cloud.gateway.client.core.ApiProperties;
import com.study.cloud.gateway.client.support.AbstractClientRegisterManager;
import com.study.cloud.gateway.common.constants.BasicConst;
import com.study.cloud.gateway.common.constants.GatewayConst;
import com.study.cloud.gateway.common.rule.ServiceDefinition;
import com.study.cloud.gateway.common.rule.ServiceInstance;
import com.study.cloud.gateway.common.util.NetUtils;
import com.study.cloud.gateway.common.util.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.event.ApplicationStartedEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * @author wangwancheng
 * @create 2025/7/19 20:05
 */
@Slf4j
@Component
public class SpringMVCClientRegisterManager extends AbstractClientRegisterManager implements ApplicationListener<ApplicationEvent>, ApplicationContextAware {

    @Autowired
    private ServerProperties serverProperties;
    //处理的bean集合
    Set<Object> set = new HashSet<>();

    private ApplicationContext applicationContext;

    public SpringMVCClientRegisterManager(ApiProperties apiProperties) {
        super(apiProperties);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        //服务启动事件
        if (event instanceof ApplicationStartedEvent) {
            try {
                doRegisterSpringMvc();
            } catch (Exception e) {
                log.error("spring mvc register error", e);
                throw new RuntimeException(e);
            }
            log.info("spring mvc api started");
        }
    }

    private void doRegisterSpringMvc() {
        Map<String, RequestMappingHandlerMapping> requestMapping = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RequestMappingHandlerMapping.class, true, false);
        for (RequestMappingHandlerMapping mapping : requestMapping.values()){
            Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();
            for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
                HandlerMethod handlerMethod = entry.getValue();

                Class<?> clazz = handlerMethod.getBeanType();
                Object bean = applicationContext.getBean(clazz);
                if (set.contains( bean)){
                    continue;
                }
                //获取服务定义信息
                ServiceDefinition serviceDefinition = ApiAnnotationScanner.getInstance().scanner( bean);
                if (serviceDefinition == null){
                    continue;
                }
                serviceDefinition.setEnvType(getApiProperties().getEnv());
                ServiceInstance serviceInstance = new ServiceInstance();
                String localIp = NetUtils.getLocalIp();
                Integer port  = serverProperties.getPort();
                String serviceInstanceId = localIp + BasicConst.COLON_SEPARATOR + port;
                String uniqueId = serviceDefinition.getUniqueId();
                String version = serviceDefinition.getVersion();
                serviceInstance.setServiceInstanceId(serviceInstanceId);
                serviceInstance.setUniqueId(uniqueId);
                serviceInstance.setIp(localIp);
                serviceInstance.setPort(port);
                serviceInstance.setRegisterTime(TimeUtil.currentTimeMillis());
                serviceInstance.setVersion( version);
                serviceInstance.setEnabled(true);
                serviceInstance.setWeight(GatewayConst.DEFAULT_WEIGHT);
                if (getApiProperties().isGray()){
                    serviceInstance.setGray(true);
                }
                register(serviceDefinition, serviceInstance);

                set.add(bean);
            }
        }

    }
}
